// 多线程环境下对象池实现。通过对象池获取股票对象。
#include <muduo/base/Mutex.h>
#include <boost/noncopyable.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/bind.hpp>
#include <string>
#include <map>
#include <stdio.h>

using muduo::MutexLock;
using muduo::MutexLockGuard;
using std::string;

// 股票类。
class Stock : boost::noncopyable {
public:
	Stock(const string &name) 
		: _name(name) {
		printf(" Stock[%p] %s\n", this, _name.c_str());
	}

	~Stock() {
		printf("~Stock[%p] %s\n", this, _name.c_str());
	}

	const string& Key() const {
		return _name;
	}

private:
	string _name;
};

// 此版本中所有的 Stock 都不会被销毁。
namespace Version1 {
	class StockFactory : boost::noncopyable {
	public:
		boost::shared_ptr<Stock> Get(const string &key) {
			MutexLockGuard lock(_mutex);
			boost::shared_ptr<Stock> &pStock = _stocks[key];
			if (!pStock)
				pStock.reset(new Stock(key));
			return pStock;
		}

	private:
		mutable MutexLock _mutex;
		std::map<string, boost::shared_ptr<Stock> > _stocks;
	};
}

// 此版本 Stock 对象可被销毁，但是 map 中无用的数据不会被清除。
namespace Version2 {
	class StockFactory : boost::noncopyable {
	public:
		boost::shared_ptr<Stock> Get(const string &key) {
			boost::shared_ptr<Stock> pStock;
			MutexLockGuard lock(_mutex);
			boost::weak_ptr<Stock> &wkStock = _stocks[key];
			pStock = wkStock.lock();
			if (!pStock) {
				pStock.reset(new Stock(key));
				wkStock = pStock;
			}
			return pStock;
		}

	private:
		mutable MutexLock _mutex;
		std::map<string, boost::weak_ptr<Stock> > _stocks;
	};
}

// 此版本会利用 shared_ptr 定制析构功能，把无用的 Stock 从 map 中移除。
// 但是有可能 Stock 析构执行时， StockFactory 已经被销毁。
namespace Version3 {
	class StockFactory : boost::noncopyable {
	public:
		boost::shared_ptr<Stock> Get(const string &key) {
			boost::shared_ptr<Stock> pStock;
			MutexLockGuard lock(_mutex);
			boost::weak_ptr<Stock> &wkStock = _stocks[key];
			pStock = wkStock.lock();

			// _1 在 boost/bind/placeholders.hpp 中定义。
			if (!pStock) {
				pStock.reset(new Stock(key), boost::bind(&StockFactory::DeleteStock, this, _1));
				wkStock = pStock;
			}
			return pStock;
		}

	private:
		void DeleteStock(Stock *stock) {
			printf("delete stock[%p]\n", stock);
			if (stock) {
				MutexLockGuard lock(_mutex);
				_stocks.erase(stock->Key());
			}
			delete stock;
		}

		mutable MutexLock _mutex;
		std::map<string, boost::weak_ptr<Stock> > _stocks;
	};
}

// 此版本是 Version3 的改进版，添加了对 StockFactory 是否已经被析构的判断。
// 为了使用 enable_shared_from_this 此时要求 StockFactory 对象必须是 heap object 且由 shared_ptr 管理其生命周期。
// 此时 StockFactory 生命周期被延长了，只要 boost::function 存在 StockFactory 就不会被销毁。
namespace Version4 {
	class StockFactory : boost::noncopyable, public boost::enable_shared_from_this<StockFactory> {
	public:
		boost::shared_ptr<Stock> Get(const string &key) {
			boost::shared_ptr<Stock> pStock;
			MutexLockGuard lock(_mutex);
			boost::weak_ptr<Stock> &wkStock = _stocks[key];
			pStock = wkStock.lock();

			if (!pStock) {
				pStock.reset(new Stock(key), boost::bind(&StockFactory::DeleteStock, shared_from_this(), _1));
				wkStock = pStock;
			}
			return pStock;
		}

	private:
		void DeleteStock(Stock *stock) {
			printf("delete stock[%p]\n", stock);
			if (stock) {
				MutexLockGuard lock(_mutex);
				_stocks.erase(stock->Key());
			}
			delete stock;
		}

		mutable MutexLock _mutex;
		std::map<string, boost::weak_ptr<Stock> > _stocks;
	};
}

// 最终版本的 StockFactory 。
class StockFactory : boost::noncopyable, public boost::enable_shared_from_this<StockFactory> {
public:
	boost::shared_ptr<Stock> Get(const string &key) {
		boost::shared_ptr<Stock> pStock;
		MutexLockGuard lock(_mutex);
		boost::weak_ptr<Stock> &wkStock = _stocks[key];
		pStock = wkStock.lock();

		if (!pStock) {
			pStock.reset(new Stock(key), 
				         boost::bind(&StockFactory::WeakDeleteCallback, 
				         	         boost::weak_ptr<StockFactory>(shared_from_this()), 
				         	         _1));
			wkStock = pStock;
		}
		return pStock;
	}

private:
	// 使用 weak_ptr 避免 StockFactory 对象的生命周期被延长。
	static void WeakDeleteCallback(const boost::weak_ptr<StockFactory> &wkFactory, Stock *stock) {
		printf("weak delete stock[%p]\n", stock);
		boost::shared_ptr<StockFactory> factory(wkFactory.lock());
		if (factory)
			factory->RemoveStock(stock);
		else
			printf("factory died\n");
		delete stock;
	}

	void RemoveStock(Stock *stock) {
		if (stock) {
			MutexLockGuard lock(_mutex);
			_stocks.erase(stock->Key());
		}
	}

	mutable MutexLock _mutex;
	std::map<string, boost::weak_ptr<Stock> > _stocks;
};

void TestLongLifeFactory()
{
	printf("\nTestLongLifeFactory\n");
	boost::shared_ptr<StockFactory> factory(new StockFactory);
	{
		boost::shared_ptr<Stock> stock = factory->Get("NYSE:IBM");
		boost::shared_ptr<Stock> stock2 = factory->Get("NYSE:IBM");
		assert(stock == stock2);
		// stock destructs here
	}
	// factory destructs here
}

void TestShortLifeFactory()
{
	printf("\nTestShortLifeFactory\n");
	boost::shared_ptr<Stock> stock;
	{
		boost::shared_ptr<StockFactory> factory(new StockFactory);
		stock = factory->Get("NYSE:IBM");
		boost::shared_ptr<Stock> stock2 = factory->Get("NYSE:IBM");
		assert(stock == stock2);
		// factory destructs here
	}
	// stock destructs here
}

int main()
{
	Version1::StockFactory sf1;
	Version2::StockFactory sf2;
	Version3::StockFactory sf3;
	boost::shared_ptr<Version4::StockFactory> sf4(new Version4::StockFactory);
	boost::shared_ptr<StockFactory> sf5(new StockFactory);

	{
		boost::shared_ptr<Stock> s1 = sf1.Get("stock1");
	}

	{
		boost::shared_ptr<Stock> s2 = sf2.Get("stock2");
	}

	{
		boost::shared_ptr<Stock> s3 = sf3.Get("stock3");
	}

	{
		boost::shared_ptr<Stock> s4 = sf4->Get("stock4");
	}

	{
		boost::shared_ptr<Stock> s5 = sf5->Get("stock5");
	}

	TestLongLifeFactory();
	TestShortLifeFactory();
	printf("exit...\n");
}
